import Foundation
import LunarSwift

public enum DateFormatStyle {
    case date
    case time
    case dateTime
    case other(String)

    var rawValue: String {
        switch self {
        case .date:
            return "yyyy-MM-dd"
        case .time:
            return "HH:mm:ss"
        case .dateTime:
            return "yyyy-MM-dd HH:mm:ss"
        case .other(let string):
            return string
        }
    }
}

public extension Date {
    func formated(_ style: DateFormatStyle = .date, language: Language = Preference.language) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = style.rawValue
        dateFormatter.locale = language.locale
        return dateFormatter.string(from: self)
    }

    var isWeekDay: Bool {
        get {
            return weekday == 0 || weekday == 6
        }
    }

    // 是否是当天
    var isCurrentDay: Bool {
        let date = Date()
        return year == date.year && month == date.month && day == date.day
    }

    var dayCount: Int {
        let calendar = Calendar.gregorian
        let range = calendar.range(of: .day, in: .month, for: self)
        return range?.count ?? 0
    }

    var year: Int {
        get {
            return components.year ?? 2023
        }
        set {
            var com = components
            com.year = newValue
            com.day = 1
            self = Calendar.gregorian.date(from: com) ?? self
            print(self)
        }
    }

    var month: Int {
        get {
            return components.month ?? 1
        }
        set {
            var com = components
            com.month = newValue
            com.day = 1
            self = Calendar.gregorian.date(from: com) ?? self
        }
    }

    var weekday: Int {
        let calendar = Calendar.gregorian
        let weekday = calendar.component(.weekday, from: self)
        return weekday - 1
    }

    var day: Int {
        let day = Calendar.gregorian.component(.day, from: self)
        return day
    }

    var weekdayOrdinal: Int {
        Calendar.current.component(.weekdayOrdinal, from: self)
    }

    var weekOfMonth: Int {
        Calendar.current.component(.weekOfMonth, from: self)
    }

    var yesterday: Date? {
        var comps = components
        guard let day = comps.day else { return nil }
        comps.day = day - 1
        return Calendar.gregorian.date(from: comps)
    }

    var tomorrow: Date? {
        var comps = components
        guard let day = comps.day else { return nil }
        comps.day = day + 1
        return Calendar.gregorian.date(from: comps)
    }

    var components: DateComponents {
        get {
            let calendar = Calendar.gregorian
            return calendar.dateComponents([.year, .month, .day, .weekday], from: self)
        }
    }

    func date(byAdding component: Calendar.Component, value: Int) -> Date {
        Calendar.gregorian.date(byAdding: component, value: value, to: self) ?? self
    }

    // 是否是同一天
    func isSameDay(as date: Date) -> Bool {
        Calendar.gregorian.isDate(self, inSameDayAs: date)
    }

    // 是否是上个月
    func isLastMonth(with date: Date) -> Bool {
        let dateComponents = date.components
        guard let curYear = components.year, let curMonth = components.month, let dateYear = dateComponents.year, let dateMonth = dateComponents.month else {
            return false
        }
        let year = curYear - dateYear
        if curMonth == 1, dateMonth == 12, year == 1 {
            return true
        } else {
            return curMonth - dateMonth == 1
        }
    }

    // 是否是下个月
    func isNextMonth(with date: Date) -> Bool {
        let dateComponents = date.components
        guard let curYear = components.year, let curMonth = components.month, let dateYear = dateComponents.year, let dateMonth = dateComponents.month else {
            return false
        }
        let year = dateYear - curYear
        if curMonth == 12, dateMonth == 1, year == 1 {
            return true
        } else {
            return dateMonth - curMonth == 1
        }
    }

    // 获取某月某天
    static func day(with month: Date = Date(), at index: Int) -> Date? {
        let calendar = Calendar.gregorian
        var comps = calendar.dateComponents([.year, .month, .day, .weekday], from: month)
        comps.day = index
        return calendar.date(from: comps)
    }
}

public extension Date {
    var startOfMonth: Date {
        let components = Calendar.gregorian.dateComponents([.year, .month], from: self)
        return Calendar.gregorian.date(from: components) ?? self
    }

    var lunarYear: Int {
        Calendar.chinese.component(.year, from: self)
    }

    var lunarMonthString: String {
        Lunar.months[lunarMonth - 1]
    }

    var lunarDayString: String {
        var value = Lunar.days[lunarDay - 1]
        if value == "初一" {
            value = isLeapMonth ? "闰" + lunarMonthString : lunarMonthString
        }
        return value
    }

    func lunarDayString(_ showMonth: Bool) -> String {
        let value = Lunar.days[lunarDay - 1]
        if showMonth, value == "初一" {
            return lunarMonthString
        }
        return value
    }

    var lunarMonth: Int {
        Calendar.chinese.component(.month, from: self)
    }

    var lunarDay: Int {
        Calendar.chinese.component(.day, from: self)
    }

    // 闰月
    var isLeapMonth: Bool {
        Calendar.chinese.dateComponents([.year, .month, .day], from: self).isLeapMonth ?? false
    }

    // 天干
    var heavenlyStems: String {
        let arr = Lunar.heavenlyStems
        let index = (lunarYear - 1) % arr.count
        return arr[index]
    }

    // 地支
    var earthlyBranches: String {
        let arr = Lunar.earthlyBranches
        let index = (lunarYear - 1) % arr.count
        return arr[index]
    }

    // 生肖
    var zodiac: String {
        let arr = Lunar.zodiacs
        let index = (lunarYear - 1) % arr.count
        return arr[index]
    }

    var lunarDate: String {
        let lunarYear = lunarYear,
            zodiacs = Lunar.zodiacs,
            heavenlyStems = Lunar.heavenlyStems,
            earthlyBranches = Lunar.earthlyBranches
        let zIndex = (lunarYear - 1) % zodiacs.count,
            hIndex = (lunarYear - 1) % heavenlyStems.count,
            eIndex = (lunarYear - 1) % earthlyBranches.count
        let lunarDay = Lunar.days[lunarDay - 1]
        return heavenlyStems[hIndex] +
        earthlyBranches[eIndex] +
        zodiacs[zIndex] + "年 " +
        (isLeapMonth ? "[闰]":"") +
        lunarMonthString +
        lunarDay
    }
}

public extension Date {
    // 太阳历
    var solar: LunarSwift.Solar {
        Solar(date: self)
    }

    // 农历
    var lunar: LunarSwift.Lunar {
        solar.lunar
    }

    // 宜
    var suitable: [String] {
        LunarUtil.getDayYi(monthGanZhi: lunar.monthInGanZhi, dayGanZhi: lunar.dayInGanZhi)
    }

    // 忌
    var taboo: [String] {
        LunarUtil.getDayJi(monthGanZhi: lunar.monthInGanZhi, dayGanZhi: lunar.dayInGanZhi)
    }

    // 二十八宿
    var xiu: String {
        lunar.xiu
    }

    // 星宿吉凶
    var xiuLuck: String {
        lunar.xiuLuck
    }

    // 星座
    var constellation: String {
        solar.xingZuo
    }
}
